using System;
using Gtk;
using System.Linq;
using Mono.Data.Sqlite;

using nwind;

namespace BanVeTau
{
	public partial class NewBus : Gtk.Window
	{
		nwind.Main db;
		public Gtk.ListStore small_stop_store;
		public Gtk.ListStore big_stop_store;
		public Gtk.ListStore schedule_store;

		public NewBus () : 
    base(Gtk.WindowType.Toplevel)
		{ 
			var conn = new SqliteConnection (
				       "DbLinqProvider=Sqlite;" +
				"Data Source=db_bvt.db"
			);
			db = new nwind.Main (conn);

			this.Build ();

			small_stop_store = new Gtk.ListStore (typeof(Stop));
			big_stop_store = new Gtk.ListStore (typeof(Stop));
			schedule_store = new Gtk.ListStore (typeof(Schedule));

			lb_form_name.LabelProp = "<span weight=\"bold\" size=\"x-large\">Create a Schedule</span>";
			lb_sche_id.LabelProp = "<span weight=\"bold\">Schedule ID</span>";
			lb_date_time_id.LabelProp = "<span weight=\"bold\">Date</span>";
			lb_start_loc.LabelProp = "<span weight=\"bold\">Start Location</span>";
			lb_stop_loc.LabelProp = "<span weight=\"bold\">Stop Location</span>";
			lb_time_consume.LabelProp = "<span weight=\"bold\">Time</span>";
			lb_seat.LabelProp = "<span weight=\"bold\">Seats</span>";

			lb_new_stop_name.LabelProp = "<span weight=\"bold\">Stop Name</span>";
			lb_new_arrive.LabelProp = "<span weight=\"bold\">Arrive</span>";
			lb_new_stoptime.LabelProp = "<span weight=\"bold\">Time</span>";
			lb_new_note.LabelProp = "<span weight=\"bold\">Note</span>";

			fr_lb_big_stop_list.LabelProp = "<span weight=\"bold\">Rests</span>";
			fr_lb_small_stop_list.LabelProp = "<span weight=\"bold\">Stops</span>";


			btn_add_stop.Label = "Add Stop";
			btn_delete_stop.Label = "Delete Stop";

			btn_add_schedule.Label = "Add Schedule";
			btn_update_schedule.Label = "Update Schedule";
			btn_delete_schedule.Label = "Delete Schedule";
			btn_load_db.Label = "Load Database";

			cb_small_stop.Label = "Stop";
			cb_big_stop.Label = "Rest";

			lb_stop_type.LabelProp = "<span weight=\"bold\">Type</span>";

			/* No column of trv small stop */
			Gtk.TreeViewColumn stop_no_col = new Gtk.TreeViewColumn ();
			stop_no_col.Title = "No";
			Gtk.CellRendererText stop_no_cell = new Gtk.CellRendererText ();
			stop_no_cell.Editable = true;
			stop_no_cell.Edited += StopNoCellEdited;
			stop_no_col.PackStart (stop_no_cell, true);
			stop_no_col.SetCellDataFunc (stop_no_cell, new Gtk.TreeCellDataFunc (RenderStopNo));


			/* Name column of trv_article_list */
			Gtk.TreeViewColumn stop_name_col = new Gtk.TreeViewColumn ();
			stop_name_col.Title = "Name";
			Gtk.CellRendererText stop_name_cell = new Gtk.CellRendererText ();
			stop_name_col.PackStart (stop_name_cell, true);
			stop_name_col.SetCellDataFunc (stop_name_cell, new Gtk.TreeCellDataFunc (RenderStopName));

			/* Third column of trv_article_list */
			Gtk.TreeViewColumn stop_arrive_col = new Gtk.TreeViewColumn ();
			stop_arrive_col.Title = "Arrive";
			Gtk.CellRendererText stop_arrive_cell = new Gtk.CellRendererText ();
			stop_arrive_col.PackStart (stop_arrive_cell, true);
			stop_arrive_col.SetCellDataFunc (stop_arrive_cell, new Gtk.TreeCellDataFunc (RenderStopArrive));

			/* Stop time column of trv_small_stop */
			Gtk.TreeViewColumn stop_time_col = new Gtk.TreeViewColumn ();
			stop_time_col.Title = "Stop Time";
			Gtk.CellRendererText stop_time_cell = new Gtk.CellRendererText ();
			stop_time_col.PackStart (stop_time_cell, true);
			stop_time_col.SetCellDataFunc (stop_time_cell, new Gtk.TreeCellDataFunc (RenderStopTime));

			/* Note column of trv_small_stop */
			Gtk.TreeViewColumn stop_note_col = new Gtk.TreeViewColumn ();
			stop_note_col.Title = "Note";
			Gtk.CellRendererText stop_note_cell = new Gtk.CellRendererText ();
			stop_note_col.PackStart (stop_note_cell, true);
			stop_note_col.SetCellDataFunc (stop_note_cell, new Gtk.TreeCellDataFunc (RenderStopNote));

			trv_small_stop.Model = small_stop_store;
			trv_small_stop.AppendColumn (stop_no_col);
			trv_small_stop.AppendColumn (stop_name_col);
			trv_small_stop.AppendColumn (stop_arrive_col);
			trv_small_stop.AppendColumn (stop_time_col);
			trv_small_stop.AppendColumn (stop_note_col);
			trv_small_stop.CursorChanged += OnSmallStopChanged;

			/************************************************************/
			/* No column of trv bit stop */
			Gtk.TreeViewColumn bstop_no_col = new Gtk.TreeViewColumn ();
			bstop_no_col.Title = "No";
			Gtk.CellRendererText bstop_no_cell = new Gtk.CellRendererText ();
			bstop_no_cell.Editable = true;
			bstop_no_cell.Edited += BstopNoCellEdited;
			bstop_no_col.PackStart (bstop_no_cell, true);
			bstop_no_col.SetCellDataFunc (bstop_no_cell, new Gtk.TreeCellDataFunc (RenderStopNo));


			/* Name column of trv_article_list */
			Gtk.TreeViewColumn bstop_name_col = new Gtk.TreeViewColumn ();
			bstop_name_col.Title = "Name";
			Gtk.CellRendererText bstop_name_cell = new Gtk.CellRendererText ();
			bstop_name_col.PackStart (bstop_name_cell, true);
			bstop_name_col.SetCellDataFunc (bstop_name_cell, new Gtk.TreeCellDataFunc (RenderStopName));

			/* Third column of trv_article_list */
			Gtk.TreeViewColumn bstop_arrive_col = new Gtk.TreeViewColumn ();
			bstop_arrive_col.Title = "Arrive";
			Gtk.CellRendererText bstop_arrive_cell = new Gtk.CellRendererText ();
			bstop_arrive_col.PackStart (bstop_arrive_cell, true);
			bstop_arrive_col.SetCellDataFunc (bstop_arrive_cell, new Gtk.TreeCellDataFunc (RenderStopArrive));

			/* Stop time column of trv_small_stop */
			Gtk.TreeViewColumn bstop_time_col = new Gtk.TreeViewColumn ();
			bstop_time_col.Title = "Stop Time";
			Gtk.CellRendererText bstop_time_cell = new Gtk.CellRendererText ();
			bstop_time_col.PackStart (bstop_time_cell, true);
			bstop_time_col.SetCellDataFunc (bstop_time_cell, new Gtk.TreeCellDataFunc (RenderStopTime));

			/* Note column of trv_small_stop */
			Gtk.TreeViewColumn bstop_note_col = new Gtk.TreeViewColumn ();
			bstop_note_col.Title = "Note";
			Gtk.CellRendererText bstop_note_cell = new Gtk.CellRendererText ();
			bstop_note_col.PackStart (bstop_note_cell, true);
			bstop_note_col.SetCellDataFunc (bstop_note_cell, new Gtk.TreeCellDataFunc (RenderStopNote));

			trv_big_stop.Model = big_stop_store;
			trv_big_stop.AppendColumn (bstop_no_col);
			trv_big_stop.AppendColumn (bstop_name_col);
			trv_big_stop.AppendColumn (bstop_arrive_col);
			trv_big_stop.AppendColumn (bstop_time_col);
			trv_big_stop.AppendColumn (bstop_note_col);
			trv_big_stop.CursorChanged += OnBigStopChanged;


			/* Note column of trv_small_stop */
			Gtk.TreeViewColumn schedule_id_col = new Gtk.TreeViewColumn ();
			schedule_id_col.Title = "Sch ID";
			Gtk.CellRendererText schedule_id_cell = new Gtk.CellRendererText ();
			schedule_id_col.PackStart (schedule_id_cell, true);
			schedule_id_col.SetCellDataFunc (schedule_id_cell, new Gtk.TreeCellDataFunc (RenderScheduleId));

			/* Note column of trv_small_stop */
			Gtk.TreeViewColumn schedule_date_col = new Gtk.TreeViewColumn ();
			schedule_date_col.Title = "Date";
			Gtk.CellRendererText schedule_date_cell = new Gtk.CellRendererText ();
			schedule_date_col.PackStart (schedule_date_cell, true);
			schedule_date_col.SetCellDataFunc (schedule_date_cell, new Gtk.TreeCellDataFunc (RenderScheduleDate));

			/* Note column of trv_small_stop */
			Gtk.TreeViewColumn schedule_startloc_col = new Gtk.TreeViewColumn ();
			schedule_startloc_col.Title = "Start Loc";
			Gtk.CellRendererText schedule_startloc_cell = new Gtk.CellRendererText ();
			schedule_startloc_col.PackStart (schedule_startloc_cell, true);
			schedule_startloc_col.SetCellDataFunc (schedule_startloc_cell, new Gtk.TreeCellDataFunc (RenderScheduleStartloc));

			/* Note column of trv_small_stop */
			Gtk.TreeViewColumn schedule_stoploc_col = new Gtk.TreeViewColumn ();
			schedule_stoploc_col.Title = "Stop Loc";
			Gtk.CellRendererText schedule_stoploc_cell = new Gtk.CellRendererText ();
			schedule_stoploc_col.PackStart (schedule_stoploc_cell, true);
			schedule_stoploc_col.SetCellDataFunc (schedule_stoploc_cell, new Gtk.TreeCellDataFunc (RenderScheduleStoploc));

			trv_registered.Model = schedule_store;
			trv_registered.AppendColumn (schedule_id_col);
			trv_registered.AppendColumn (schedule_date_col);
			trv_registered.AppendColumn (schedule_startloc_col);
			trv_registered.AppendColumn (schedule_stoploc_col);
			trv_registered.CursorChanged += OnScheduleChanged;
		}
		/* Various function to render when stop selected stop change */
		private void BstopNoCellEdited (object o, Gtk.EditedArgs args)
		{
			Gtk.TreeIter iter;
			big_stop_store.GetIter (out iter, new Gtk.TreePath (args.Path));

			Stop sto = (Stop)big_stop_store.GetValue (iter, 0);
			sto.StopNo = Int32.Parse (args.NewText);
		}

		private void StopNoCellEdited (object o, Gtk.EditedArgs args)
		{
			Gtk.TreeIter iter;
			small_stop_store.GetIter (out iter, new Gtk.TreePath (args.Path));

			Stop sto = (Stop)small_stop_store.GetValue (iter, 0);
			sto.StopNo = Int32.Parse (args.NewText);
		}

		private void OnBigStopChanged (object obj, EventArgs args)
		{
			Gtk.TreeModel model = trv_big_stop.Model;
			Gtk.TreeIter iter;
			trv_big_stop.Selection.GetSelected (out model, out iter);

			Stop sto = (Stop)model.GetValue (iter, 0);

			cb_big_stop.Active = true;
			cb_small_stop.Active = false;
			new_stop_fields_refresh (sto);
		}

		private void OnSmallStopChanged (object obj, EventArgs args)
		{
			Gtk.TreeModel model = trv_small_stop.Model;
			Gtk.TreeIter iter;
			trv_small_stop.Selection.GetSelected (out model, out iter);

			Stop sto = (Stop)model.GetValue (iter, 0);

			cb_small_stop.Active = true;
			cb_big_stop.Active = false;
			new_stop_fields_refresh (sto);
		}

		public int new_stop_fields_refresh (Stop sto)
		{
			e_new_stop_name.Text = sto.StopName;
			e_new_arrive.Text = sto.ArriveTime;
			e_new_stoptime.Text = sto.StopTime;
			e_new_note.Text = sto.StopNote;

			return 1;
		}

		private void OnScheduleChanged (object obj, EventArgs args)
		{
			Gtk.TreeModel model = trv_registered.Model;
			Gtk.TreeIter iter;
			trv_registered.Selection.GetSelected (out model, out iter);

			Schedule sch = (Schedule)model.GetValue (iter, 0);

			small_stop_store_refresh (sch);
			big_stop_store_refresh (sch);

			e_sche_id.Text = sch.ScheduleID;
			e_date_time.Text = sch.Mdate;
			e_start_loc.Text = sch.StartLoc;
			e_stop_loc.Text = sch.StopLoc;
			e_time_consume.Text = sch.TimeConsume;
			e_seats.Text = sch.Seats.ToString ();
			/* FIXME : assign sch value to fields */
		}

		/* when change schedule */
		public int small_stop_store_refresh (Schedule sch)
		{
			small_stop_store.Clear ();
			var small_stops = from sm in db.Stop
	where sm.ScheduleID == sch.ScheduleID && sm.StopType == "stop"
	select sm;

			foreach (Stop sto in small_stops) {
				small_stop_store.AppendValues (sto);
			}
			return 1;
		}

		public int big_stop_store_refresh (Schedule sch)
		{
			big_stop_store.Clear ();
			var big_stops = from bi in db.Stop
	where bi.ScheduleID == sch.ScheduleID && bi.StopType == "rest"
	select bi;

			foreach (Stop sto in big_stops) {
				big_stop_store.AppendValues (sto);
			}
			return 1;
		}
	
		/* Various function to render text in columns */

		private void RenderScheduleId (Gtk.TreeViewColumn col, Gtk.CellRenderer cell, Gtk.TreeModel model, Gtk.TreeIter iter)
		{

			Schedule sch = (Schedule)model.GetValue (iter, 0);

			(cell as Gtk.CellRendererText).Text = sch.ScheduleID;
		}

		private void RenderScheduleDate (Gtk.TreeViewColumn col, Gtk.CellRenderer cell, Gtk.TreeModel model, Gtk.TreeIter iter)
		{
			Schedule sch = (Schedule)model.GetValue (iter, 0);
			(cell as Gtk.CellRendererText).Text = sch.Mdate;
		}

		private void RenderScheduleStartloc (Gtk.TreeViewColumn col, Gtk.CellRenderer cell, Gtk.TreeModel model, Gtk.TreeIter iter)
		{
			Schedule sch = (Schedule)model.GetValue (iter, 0);
			(cell as Gtk.CellRendererText).Text = sch.StartLoc;
		}

		private void RenderScheduleStoploc (Gtk.TreeViewColumn col, Gtk.CellRenderer cell, Gtk.TreeModel model, Gtk.TreeIter iter)
		{
			Schedule sch = (Schedule)model.GetValue (iter, 0);
			(cell as Gtk.CellRendererText).Text = sch.StopLoc;
		}
    
		private void RenderStopNo (Gtk.TreeViewColumn column, Gtk.CellRenderer cell, Gtk.TreeModel model, Gtk.TreeIter iter)
		{
			Stop sto = (Stop)model.GetValue (iter, 0);

			(cell as Gtk.CellRendererText).Text = sto.StopNo.ToString ();
		}

		private void RenderStopName (Gtk.TreeViewColumn column, Gtk.CellRenderer cell, Gtk.TreeModel model, Gtk.TreeIter iter)
		{
			Stop sto = (Stop)model.GetValue (iter, 0);

			(cell as Gtk.CellRendererText).Text = sto.StopName;
		}

		private void RenderStopArrive (Gtk.TreeViewColumn column, Gtk.CellRenderer cell, Gtk.TreeModel model, Gtk.TreeIter iter)
		{
			Stop sto = (Stop)model.GetValue (iter, 0);

			(cell as Gtk.CellRendererText).Text = sto.ArriveTime;
		}
    
		private void RenderStopTime (Gtk.TreeViewColumn column, Gtk.CellRenderer cell, Gtk.TreeModel model, Gtk.TreeIter iter)
		{
			Stop sto = (Stop)model.GetValue (iter, 0);

			(cell as Gtk.CellRendererText).Text = sto.StopTime;
		}

		private void RenderStopNote (Gtk.TreeViewColumn column, Gtk.CellRenderer cell, Gtk.TreeModel model, Gtk.TreeIter iter)
		{
			Stop sto = (Stop)model.GetValue (iter, 0);

			(cell as Gtk.CellRendererText).Text = sto.StopNote;
		}

		protected void OnDeleteStop (object sender, EventArgs e)
		{
			Gtk.TreeModel model = big_stop_store;
			Gtk.TreeIter iter;
			bool got;

			got = trv_big_stop.Selection.GetSelected (out model, out iter);

			if (got != false) {
				big_stop_store.Remove (ref iter);
			}

			model = small_stop_store;

			got = trv_small_stop.Selection.GetSelected (out model, out iter);

			if (got != false) {
				small_stop_store.Remove (ref iter);
			}
		}

		protected void OnAddStop (object sender, EventArgs e)
		{
			Stop sto;
			Gtk.TreeModel model = trv_registered.Model;
			Gtk.TreeIter iter;
			trv_registered.Selection.GetSelected (out model, out iter);

			Schedule sch = (Schedule)model.GetValue (iter, 0);

			sto = new Stop ();
			sto.StopName = e_new_stop_name.Text;
			sto.ArriveTime = e_new_arrive.Text;
			sto.StopTime = e_new_stoptime.Text;
			sto.StopNote = e_new_note.Text;
			sto.ScheduleID = sch.ScheduleID;
			sto.ArriveTime = e_new_arrive.Text;
			sto.StopTime = e_new_stoptime.Text;
			sto.StopNote = e_new_note.Text;

			if (cb_big_stop.Active == true) {
				sto.StopType = "rest";
				big_stop_store.AppendValues (sto);
			}
			if (cb_small_stop.Active == true) {
				sto.StopType = "stop";
				small_stop_store.AppendValues (sto);
			}
		}

		protected void OnLoadDatabase (object sender, EventArgs e)
		{
			var schedules = from sc in db.Schedule
	select sc;

			foreach (Schedule sch in schedules) {
				schedule_store.AppendValues (sch);
			}
		}

		protected void OnAddSchedule (object sender, EventArgs e)
		{
			/* TODO: Test me */
			Schedule sch = new Schedule ();
			sch.ScheduleID = e_sche_id.Text;
			sch.Mdate = e_date_time.Text;
			sch.StartLoc = e_start_loc.Text;
			sch.StopLoc = e_stop_loc.Text;
			sch.TimeConsume = e_time_consume.Text;
			sch.Seats = Int32.Parse (e_seats.Text);

			add_schedule (sch);
      
			Console.WriteLine ("Add schedule successfull!");
			add_big_stops (sch);
			Console.WriteLine ("Add big stops successfull!");
			add_small_stops (sch);
			Console.WriteLine ("Add stops successfull!");
		}

		public int add_schedule (Schedule sch)
		{
			db.Schedule.InsertOnSubmit (sch);
			db.SubmitChanges ();
			return 1;
		}

		public int add_big_stops (Schedule sch)
		{
			int col = 0;
			Stop sto;
			foreach (object[] row in big_stop_store) {
				sto = (Stop)row [col];
				add_stop (sto, sch);
			}
			return 1;
		}

		public int add_stop (Stop sto, Schedule sch)
		{
			/* TODO: test me */
			sto.ScheduleID = sch.ScheduleID;
			db.Stop.InsertOnSubmit (sto);
			db.SubmitChanges ();
			return 1;
		}

		public int add_small_stops (Schedule sch)
		{
			int col = 0;
			Stop sto;
			foreach (object[] row in small_stop_store) {
				sto = (Stop)row [col];
				add_stop (sto, sch);
			}
			return 1;
		}

		protected void OnUpdateSchedule (object sender, EventArgs e)
		{
			/* TODO : test me */
			Gtk.TreeModel model = trv_registered.Model;
			Gtk.TreeIter iter;
			trv_registered.Selection.GetSelected (out model, out iter);

			Schedule sch = (Schedule)model.GetValue (iter, 0);

			/* FIXME: i'm lazy */
			delete_schedule (sch);
			delete_stops (sch);
			sch = new Schedule ();

			sch.ScheduleID = e_sche_id.Text;
			sch.Mdate = e_date_time.Text;
			sch.StartLoc = e_start_loc.Text;
			sch.StopLoc = e_stop_loc.Text;
			sch.TimeConsume = e_time_consume.Text;
			sch.Seats = Int32.Parse (e_seats.Text);
			model.SetValue (iter, 0, sch);
      
			add_schedule (sch);
			add_big_stops (sch);
			add_small_stops (sch);
      
		}

		protected void OnDeleteSchedule (object sender, EventArgs e)
		{
			/* TODO: test me */
			Gtk.TreeModel model = trv_registered.Model;
			Gtk.TreeIter iter;
			trv_registered.Selection.GetSelected (out model, out iter);

			Schedule sch = (Schedule)model.GetValue (iter, 0);

			delete_schedule (sch);
			delete_stops (sch);
			delete_tickets (sch);

			sch = null;
			schedule_store.Remove (ref iter);
		}

		public int delete_schedule (Schedule schedule)
		{
			/* TODO : test me */
			var will_del_sch = from sch in db.Schedule
	where sch.ScheduleID == schedule.ScheduleID
	select sch;

			db.Schedule.DeleteAllOnSubmit (will_del_sch);
			db.SubmitChanges ();
			return 1;
		}

		public int delete_stops (Schedule schedule)
		{
			var will_del_sto = from sto in db.Stop
	where sto.ScheduleID == schedule.ScheduleID
	select sto;

			db.Stop.DeleteAllOnSubmit (will_del_sto);
			db.SubmitChanges ();
			return 1;
		}

		public int delete_tickets (Schedule schedule)
		{
			var will_del_tik = from tik in db.Ticket
	where tik.ScheduleID == schedule.ScheduleID
	select tik;

			db.Ticket.DeleteAllOnSubmit (will_del_tik);
			db.SubmitChanges ();
			return 1;
		}
	}
}

